package com.zhouxiaoxuan13.consumer.controller;

import com.zhouxiaoxuan13.consumer.dto.FreshProduct;
import com.zhouxiaoxuan13.consumer.dto.Promotion;
import com.zhouxiaoxuan13.consumer.dto.PromotionDetailDTO;
import com.zhouxiaoxuan13.consumer.feign.FreshProductServiceClient;
import com.zhouxiaoxuan13.consumer.feign.LoadBalancerServiceClient;
import com.zhouxiaoxuan13.consumer.feign.PromotionServiceClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;

/**
 * OpenFeign演示控制器
 * 展示如何使用OpenFeign进行微服务间的接口调用
 * 包含负载均衡、容错和熔断器功能
 */
@Slf4j
@RestController
@RequestMapping("/feign")
@CrossOrigin(originPatterns = "*")
public class FeignController {

    @Autowired
    private PromotionServiceClient promotionServiceClient;

    @Autowired
    private FreshProductServiceClient freshProductServiceClient;

    @Autowired
    private LoadBalancerServiceClient loadBalancerServiceClient;

    private final AtomicLong requestCounter = new AtomicLong(0);

    // ==================== 促销服务相关接口 ====================

    /**
     * 使用Feign获取所有促销信息
     */
    @GetMapping("/promotions")
    public ResponseEntity<?> getAllPromotions() {
        try {
            long requestNum = requestCounter.incrementAndGet();
            log.info("=== Feign调用获取所有促销信息 #" + requestNum + " ===");
            
            ResponseEntity<List<PromotionDetailDTO>> result = promotionServiceClient.getAllPromotions();
            
            Map<String, Object> response = new HashMap<>();
            response.put("requestNumber", requestNum);
            response.put("data", result.getBody());
            response.put("statusCode", result.getStatusCodeValue());
            response.put("callType", "OpenFeign + LoadBalancer");
            response.put("timestamp", System.currentTimeMillis());
            
            return ResponseEntity.ok(response);
        } catch (Exception e) {
            log.error("Feign调用失败: ", e);
            return ResponseEntity.status(500).body("Feign调用失败: " + e.getMessage());
        }
    }

    /**
     * 使用Feign获取活跃促销信息
     */
    @GetMapping("/promotions/active")
    public ResponseEntity<?> getActivePromotions() {
        try {
            long requestNum = requestCounter.incrementAndGet();
            log.info("=== Feign调用获取活跃促销信息 #" + requestNum + " ===");
            
            ResponseEntity<List<PromotionDetailDTO>> result = promotionServiceClient.getActivePromotions();
            
            Map<String, Object> response = new HashMap<>();
            response.put("requestNumber", requestNum);
            response.put("data", result.getBody());
            response.put("statusCode", result.getStatusCodeValue());
            response.put("callType", "OpenFeign + LoadBalancer");
            response.put("timestamp", System.currentTimeMillis());
            
            return ResponseEntity.ok(response);
        } catch (Exception e) {
            log.error("Feign调用失败: ", e);
            return ResponseEntity.status(500).body("Feign调用失败: " + e.getMessage());
        }
    }

    /**
     * 使用Feign根据ID获取促销信息
     */
    @GetMapping("/promotions/{id}")
    public ResponseEntity<?> getPromotionById(@PathVariable Long id) {
        try {
            long requestNum = requestCounter.incrementAndGet();
            log.info("=== Feign调用获取促销信息 ID: {} #" + requestNum + " ===", id);
            
            ResponseEntity<Promotion> result = promotionServiceClient.getPromotionById(id);
            
            Map<String, Object> response = new HashMap<>();
            response.put("requestNumber", requestNum);
            response.put("data", result.getBody());
            response.put("statusCode", result.getStatusCodeValue());
            response.put("callType", "OpenFeign + LoadBalancer");
            response.put("timestamp", System.currentTimeMillis());
            
            return ResponseEntity.ok(response);
        } catch (Exception e) {
            log.error("Feign调用失败: ", e);
            return ResponseEntity.status(500).body("Feign调用失败: " + e.getMessage());
        }
    }

    /**
     * 使用Feign创建促销
     */
    @PostMapping("/promotions")
    public ResponseEntity<?> createPromotion(@RequestBody Promotion promotion) {
        try {
            long requestNum = requestCounter.incrementAndGet();
            log.info("=== Feign调用创建促销 #" + requestNum + " ===");
            
            ResponseEntity<Promotion> result = promotionServiceClient.createPromotion(promotion);
            
            Map<String, Object> response = new HashMap<>();
            response.put("requestNumber", requestNum);
            response.put("data", result.getBody());
            response.put("statusCode", result.getStatusCodeValue());
            response.put("callType", "OpenFeign + LoadBalancer");
            response.put("timestamp", System.currentTimeMillis());
            
            return ResponseEntity.ok(response);
        } catch (Exception e) {
            log.error("Feign调用失败: ", e);
            return ResponseEntity.status(500).body("Feign调用失败: " + e.getMessage());
        }
    }

    // ==================== 生鲜商品服务相关接口 ====================

    /**
     * 使用Feign获取所有生鲜商品
     */
    @GetMapping("/fresh-products")
    public ResponseEntity<?> getAllFreshProducts() {
        try {
            long requestNum = requestCounter.incrementAndGet();
            log.info("=== Feign调用获取所有生鲜商品 #" + requestNum + " ===");
            
            ResponseEntity<List<FreshProduct>> result = freshProductServiceClient.getAllFreshProducts();
            
            Map<String, Object> response = new HashMap<>();
            response.put("requestNumber", requestNum);
            response.put("data", result.getBody());
            response.put("statusCode", result.getStatusCodeValue());
            response.put("callType", "OpenFeign + LoadBalancer");
            response.put("timestamp", System.currentTimeMillis());
            
            return ResponseEntity.ok(response);
        } catch (Exception e) {
            log.error("Feign调用失败: ", e);
            return ResponseEntity.status(500).body("Feign调用失败: " + e.getMessage());
        }
    }

    /**
     * 使用Feign获取促销商品
     */
    @GetMapping("/fresh-products/promotions")
    public ResponseEntity<?> getPromotionProducts() {
        try {
            long requestNum = requestCounter.incrementAndGet();
            log.info("=== Feign调用获取促销商品 #" + requestNum + " ===");
            
            ResponseEntity<List<FreshProduct>> result = freshProductServiceClient.getPromotionProducts();
            
            Map<String, Object> response = new HashMap<>();
            response.put("requestNumber", requestNum);
            response.put("data", result.getBody());
            response.put("statusCode", result.getStatusCodeValue());
            response.put("callType", "OpenFeign + LoadBalancer");
            response.put("timestamp", System.currentTimeMillis());
            
            return ResponseEntity.ok(response);
        } catch (Exception e) {
            log.error("Feign调用失败: ", e);
            return ResponseEntity.status(500).body("Feign调用失败: " + e.getMessage());
        }
    }

    /**
     * 使用Feign根据种类获取商品
     */
    @GetMapping("/fresh-products/category/{category}")
    public ResponseEntity<?> getFreshProductsByCategory(@PathVariable String category) {
        try {
            long requestNum = requestCounter.incrementAndGet();
            log.info("=== Feign调用获取种类商品: {} #" + requestNum + " ===", category);
            
            ResponseEntity<List<FreshProduct>> result = freshProductServiceClient.getFreshProductsByCategory(category);
            
            Map<String, Object> response = new HashMap<>();
            response.put("requestNumber", requestNum);
            response.put("data", result.getBody());
            response.put("statusCode", result.getStatusCodeValue());
            response.put("callType", "OpenFeign + LoadBalancer");
            response.put("timestamp", System.currentTimeMillis());
            
            return ResponseEntity.ok(response);
        } catch (Exception e) {
            log.error("Feign调用失败: ", e);
            return ResponseEntity.status(500).body("Feign调用失败: " + e.getMessage());
        }
    }

    // ==================== 负载均衡测试相关接口 ====================

    /**
     * 使用Feign测试负载均衡
     */
    @GetMapping("/loadbalancer/current-instance")
    public ResponseEntity<?> getCurrentInstance() {
        try {
            long requestNum = requestCounter.incrementAndGet();
            log.info("=== Feign调用负载均衡测试 #" + requestNum + " ===");
            
            ResponseEntity<Map<String, Object>> result = loadBalancerServiceClient.getCurrentInstance();
            
            Map<String, Object> response = new HashMap<>();
            response.put("consumerRequestNumber", requestNum);
            response.put("providerResponse", result.getBody());
            response.put("statusCode", result.getStatusCodeValue());
            response.put("callType", "OpenFeign + LoadBalancer");
            response.put("timestamp", System.currentTimeMillis());
            
            return ResponseEntity.ok(response);
        } catch (Exception e) {
            log.error("Feign调用失败: ", e);
            return ResponseEntity.status(500).body("Feign调用失败: " + e.getMessage());
        }
    }

    /**
     * 使用Feign获取服务统计信息
     */
    @GetMapping("/loadbalancer/stats")
    public ResponseEntity<?> getStats() {
        try {
            long requestNum = requestCounter.incrementAndGet();
            log.info("=== Feign调用获取统计信息 #" + requestNum + " ===");
            
            ResponseEntity<Map<String, Object>> result = loadBalancerServiceClient.getStats();
            
            Map<String, Object> response = new HashMap<>();
            response.put("consumerRequestNumber", requestNum);
            response.put("providerResponse", result.getBody());
            response.put("statusCode", result.getStatusCodeValue());
            response.put("callType", "OpenFeign + LoadBalancer");
            response.put("timestamp", System.currentTimeMillis());
            
            return ResponseEntity.ok(response);
        } catch (Exception e) {
            log.error("Feign调用失败: ", e);
            return ResponseEntity.status(500).body("Feign调用失败: " + e.getMessage());
        }
    }

    // ==================== 批量测试接口 ====================

    /**
     * 批量测试Feign负载均衡效果
     */
    @GetMapping("/test/load-balance")
    public ResponseEntity<?> testLoadBalance(@RequestParam(value = "times", defaultValue = "10") int times) {
        Map<String, Integer> instanceCounts = new HashMap<>();
        Map<String, Object> result = new HashMap<>();
        
        log.info("=== 开始Feign负载均衡测试，测试次数: {} ===", times);
        
        for (int i = 0; i < times; i++) {
            try {
                ResponseEntity<Map<String, Object>> response = loadBalancerServiceClient.getCurrentInstance();
                if (response.getBody() != null) {
                    String port = String.valueOf(response.getBody().get("port"));
                    String instanceKey = "instance-" + port;
                    instanceCounts.put(instanceKey, instanceCounts.getOrDefault(instanceKey, 0) + 1);
                    log.info("第{}次Feign调用: {}", (i + 1), instanceKey);
                }
            } catch (Exception e) {
                log.error("第{}次Feign调用失败: {}", (i + 1), e.getMessage());
            }
        }
        
        result.put("totalTests", times);
        result.put("instanceDistribution", instanceCounts);
        result.put("callType", "OpenFeign Batch Test");
        result.put("timestamp", System.currentTimeMillis());
        
        log.info("=== Feign负载均衡测试结果 ===");
        log.info("实例分布: {}", instanceCounts);

        return ResponseEntity.ok(result);
    }

    // ==================== 熔断器测试接口 ====================

    /**
     * 测试慢响应熔断
     */
    @GetMapping("/circuit-breaker/slow")
    public ResponseEntity<?> testSlowCircuitBreaker(
            @RequestParam(value = "delay", defaultValue = "5000") int delay,
            @RequestParam(value = "times", defaultValue = "3") int times) {
        try {
            long testNum = requestCounter.incrementAndGet();
            log.info("=== Feign慢响应熔断测试 #{} ===", testNum);

            List<Map<String, Object>> results = new ArrayList<>();

            for (int i = 1; i <= times; i++) {
                try {
                    long startTime = System.currentTimeMillis();
                    ResponseEntity<Map<String, Object>> response = loadBalancerServiceClient.slowResponse(delay);
                    long endTime = System.currentTimeMillis();

                    Map<String, Object> callResult = new HashMap<>();
                    callResult.put("callNumber", i);
                    callResult.put("status", "success");
                    callResult.put("responseTime", endTime - startTime + "ms");
                    callResult.put("data", response.getBody());
                    results.add(callResult);

                } catch (Exception e) {
                    Map<String, Object> callResult = new HashMap<>();
                    callResult.put("callNumber", i);
                    callResult.put("status", "error");
                    callResult.put("error", e.getMessage());
                    results.add(callResult);
                }
            }

            Map<String, Object> response = new HashMap<>();
            response.put("testNumber", testNum);
            response.put("testType", "慢响应熔断测试");
            response.put("delay", delay + "ms");
            response.put("totalCalls", times);
            response.put("results", results);
            response.put("timestamp", System.currentTimeMillis());

            return ResponseEntity.ok(response);
        } catch (Exception e) {
            log.error("慢响应熔断测试失败: {}", e.getMessage());
            return ResponseEntity.status(500).body("测试失败: " + e.getMessage());
        }
    }

    /**
     * 测试异常熔断
     */
    @GetMapping("/circuit-breaker/error")
    public ResponseEntity<?> testErrorCircuitBreaker(
            @RequestParam(value = "errorRate", defaultValue = "80") int errorRate,
            @RequestParam(value = "times", defaultValue = "10") int times) {
        try {
            long testNum = requestCounter.incrementAndGet();
            log.info("=== Feign异常熔断测试 #{} ===", testNum);

            List<Map<String, Object>> results = new ArrayList<>();
            int successCount = 0;
            int errorCount = 0;
            int fallbackCount = 0;

            for (int i = 1; i <= times; i++) {
                try {
                    ResponseEntity<Map<String, Object>> response = loadBalancerServiceClient.errorResponse(errorRate);
                    Map<String, Object> responseBody = response.getBody();

                    Map<String, Object> callResult = new HashMap<>();
                    callResult.put("callNumber", i);

                    if (responseBody != null && "fallback".equals(responseBody.get("status"))) {
                        callResult.put("status", "fallback");
                        fallbackCount++;
                    } else {
                        callResult.put("status", "success");
                        successCount++;
                    }
                    callResult.put("data", responseBody);
                    results.add(callResult);

                } catch (Exception e) {
                    Map<String, Object> callResult = new HashMap<>();
                    callResult.put("callNumber", i);
                    callResult.put("status", "error");
                    callResult.put("error", e.getMessage());
                    results.add(callResult);
                    errorCount++;
                }
            }

            Map<String, Object> response = new HashMap<>();
            response.put("testNumber", testNum);
            response.put("testType", "异常熔断测试");
            response.put("errorRate", errorRate + "%");
            response.put("totalCalls", times);
            response.put("successCount", successCount);
            response.put("errorCount", errorCount);
            response.put("fallbackCount", fallbackCount);
            response.put("results", results);
            response.put("timestamp", System.currentTimeMillis());

            return ResponseEntity.ok(response);
        } catch (Exception e) {
            log.error("异常熔断测试失败: {}", e.getMessage());
            return ResponseEntity.status(500).body("测试失败: " + e.getMessage());
        }
    }

    /**
     * 测试服务不可用熔断
     */
    @GetMapping("/circuit-breaker/unavailable")
    public ResponseEntity<?> testUnavailableCircuitBreaker(@RequestParam(value = "times", defaultValue = "5") int times) {
        try {
            long testNum = requestCounter.incrementAndGet();
            log.info("=== Feign服务不可用熔断测试 #{} ===", testNum);

            List<Map<String, Object>> results = new ArrayList<>();
            int successCount = 0;
            int errorCount = 0;
            int fallbackCount = 0;

            for (int i = 1; i <= times; i++) {
                try {
                    ResponseEntity<Map<String, Object>> response = loadBalancerServiceClient.unavailableResponse();
                    Map<String, Object> responseBody = response.getBody();

                    Map<String, Object> callResult = new HashMap<>();
                    callResult.put("callNumber", i);

                    if (responseBody != null && "fallback".equals(responseBody.get("status"))) {
                        callResult.put("status", "fallback");
                        fallbackCount++;
                    } else {
                        callResult.put("status", "success");
                        successCount++;
                    }
                    callResult.put("data", responseBody);
                    results.add(callResult);

                } catch (Exception e) {
                    Map<String, Object> callResult = new HashMap<>();
                    callResult.put("callNumber", i);
                    callResult.put("status", "error");
                    callResult.put("error", e.getMessage());
                    results.add(callResult);
                    errorCount++;
                }
            }

            Map<String, Object> response = new HashMap<>();
            response.put("testNumber", testNum);
            response.put("testType", "服务不可用熔断测试");
            response.put("totalCalls", times);
            response.put("successCount", successCount);
            response.put("errorCount", errorCount);
            response.put("fallbackCount", fallbackCount);
            response.put("results", results);
            response.put("timestamp", System.currentTimeMillis());

            return ResponseEntity.ok(response);
        } catch (Exception e) {
            log.error("服务不可用熔断测试失败: {}", e.getMessage());
            return ResponseEntity.status(500).body("测试失败: " + e.getMessage());
        }
    }
}
